################################################################################
# This file is part of the Mist compiler.                                      #
#                                                                              #
# Copyright (C) 2008, 2009 The Mist project                                    #
#                                                                              #
# For a list of contributors, see the COMMITTERS file.                         #
#                                                                              #
# The Mist compiler is free software: you can redistribute it and/or modify    #
# it under the terms of the GNU General Public License as published by         #
# the Free Software Foundation, either version 3 of the License, or            #
# (at your option) any later version.                                          #
#                                                                              #
# The Mist compiler is distributed in the hope that it will be useful,         #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# in the COPYING file. If not, see <http://www.gnu.org/licenses/>.             #
################################################################################

################################################################################
ROOT = .
################################################################################

# The following variables specify the linux tools used to build the compiler.
#
BISON = bison
FLEX  = flex -w
CXX   = g++
RM    = rm -f
TOUCH = touch
ECHO  = echo
DIFF  = diff

# The following variables specify the flags passed to the C++ compiler.
#
CXXFLAGS      = -pipe -Wall -Wno-parentheses -g -I$(ROOT)
LINKFLAGS     = -lgmpxx -lgmp -lboost_program_options -lboost_filesystem -lboost_regex
TESTLINKFLAGS = -lboost_test_exec_monitor -lboost_system

################################################################################

# PROGRAM_FILES contains the list of executables that can be produced, linking
# all object files plus the corresponding source file.
#
PROGRAM_FILES = mist

# SOURCE_FILES lists all source files (.cpp, .yy, .ll) of the compiler, except
# for those source files corresponding to PROGRAM_FILES.
#
# This list needs to be kept up to date with new source files in the project.
# Every time you add a new file to this list, do a `make depclean` before you
# build the compiler.
#
SOURCE_FILES = common/assert.cpp                       \
               common/numeric.cpp                      \
               common/outputproducer.cpp               \
               common/string.cpp                       \
               accesstype.cpp                          \
               codestream.cpp                          \
               copyast.cpp                             \
               echo.cpp                                \
               exclusivevisitor.cpp                    \
               expression.accesstypeof.cpp             \
               expression.sideeffectreach.cpp          \
               expression.typeof.cpp                   \
               finderror1.cpp                          \
               findproof.cpp                           \
               findreferences.cpp                      \
               functiondeclaration.sideeffectreach.cpp \
               keyinput.cpp                            \
               keysolver.cpp                           \
               location.cpp                            \
               message.cpp                             \
               messageinfo.cpp                         \
               messages.cpp                            \
               navigator.cpp                           \
               node.scope.cpp                          \
               operator.cpp                            \
               position.cpp                            \
               reference.resolved.cpp                  \
               setparents.cpp                          \
               symbol.cpp                              \
               testvisit.cpp                           \
               tree.cpp                                \
               typespec.cpp                            \
               parser.yy                               \
               lexer.ll

################################################################################

#
# Intermediate variables, used to make the coming building rules more readable.
#

BISON_FILES = $(filter %.yy,$(SOURCE_FILES))

FLEX_FILES  = $(filter %.ll,$(SOURCE_FILES))

SOURCES = $(BISON_FILES:.yy=.tab.cpp) \
          $(FLEX_FILES:.ll=.lex.cpp)  \
          $(filter %.cpp,$(SOURCE_FILES))

OBJECTS = $(SOURCES:.cpp=.o)

PROGRAM_OBJECTS = $(PROGRAM_FILES:=.o)

DEPENDENCIES = $(SOURCES:.cpp=.d)   \
               $(PROGRAM_FILES:=.d) \
               test/test.d

STATIC_BISON_HEADERS = location.hh position.hh

ANY_BISON_FILE = $(firstword $(BISON_FILES))

GENERATED_HEADERS = $(STATIC_BISON_HEADERS)     \
                    $(BISON_FILES:.yy=.tab.hpp) \
                    $(FLEX_FILES:.ll=.lex.hpp)

################################################################################

#
# The special make targets that specify phony and secondary targets of the
# build process.
#

.PHONY: all clean depclean test

.SECONDARY: $(OBJECTS) $(PROGRAM_OBJECTS) \
            $(BISON_FILES:.yy=.tab.cpp)   \
            $(BISON_FILES:.yy=.tab.hpp)   \
            $(FLEX_FILES:.ll=.lex.cpp)    \
            $(FLEX_FILES:.ll=.lex.hpp)    \
            test/test.o

.SUFFIXES:

################################################################################

#
# The rules that actually specify the building process.
#

# Build everything and run all unit-tests.
#
all: $(PROGRAM_FILES) test

# Remove every automatically generated file.
#
clean: depclean
	$(RM) *~ *.o *.output *.lex.* *.tab.* *.hh $(PROGRAM_FILES) common/*.o common/*~ test/test test/tested test/*.o test/*~

# Remove the dependency (.d) files. This is necessary after SOURCE_FILES
# changes, before building again. There is usually no need to `make clean`.
#
depclean:
	$(RM) *.d common/*.d test/*.d

# Run all unit-tests.
#
test: test/tested

test/test: $(OBJECTS) test/test.o
	@ $(ECHO) "Linking: <sources>.o $@.o"
	@ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^ $(TESTLINKFLAGS)

test/tested: test/test
	@ BOOST_TEST_CATCH_SYSTEM_ERRORS="no" ./test/test
	@ $(TOUCH) test/tested

ifeq (,$(findstring $(MAKECMDGOALS), clean depclean))
-include $(DEPENDENCIES)
endif

%.lex.cpp %.lex.hpp: %.ll
	@ if [ -e "$*.lex.cpp" ]; then cp --preserve=timestamps $*.lex.cpp $*.lex.cpp.old; fi;
	@ if [ -e "$*.lex.hpp" ]; then cp --preserve=timestamps $*.lex.hpp $*.lex.hpp.old; fi;
	$(FLEX) $<
	@ if [ -e "$*.lex.cpp.old" ]; then if diff $*.lex.cpp $*.lex.cpp.old > /dev/null; then $(TOUCH) -m $*.lex.cpp --reference=$*.lex.cpp.old; $(TOUCH) -m $< --reference=$*.lex.cpp.old; $(RM) $*.lex.cpp.old; fi; fi;
	@ if [ -e "$*.lex.hpp.old" ]; then if diff $*.lex.hpp $*.lex.hpp.old > /dev/null; then $(TOUCH) -m $*.lex.hpp --reference=$*.lex.hpp.old; $(TOUCH) -m $< --reference=$*.lex.hpp.old; $(RM) $*.lex.hpp.old; fi; fi;

%.tab.cpp %.tab.hpp: %.yy
	@ if [ -e "$*.tab.cpp" ]; then cp --preserve=timestamps $*.tab.cpp $*.tab.cpp.old; fi;
	@ if [ -e "$*.tab.hpp" ]; then cp --preserve=timestamps $*.tab.hpp $*.tab.hpp.old; fi;
	$(BISON) $<
	@ if [ -e "$*.tab.cpp.old" ]; then if diff $*.tab.cpp $*.tab.cpp.old > /dev/null; then $(TOUCH) -m $*.tab.cpp --reference=$*.tab.cpp.old; $(TOUCH) -m $< --reference=$*.tab.cpp.old; $(RM) $*.tab.cpp.old; fi; fi;
	@ if [ -e "$*.tab.hpp.old" ]; then if diff $*.tab.hpp $*.tab.hpp.old > /dev/null; then $(TOUCH) -m $*.tab.hpp --reference=$*.tab.hpp.old; $(TOUCH) -m $< --reference=$*.tab.hpp.old; $(RM) $*.tab.hpp.old; fi; fi;
	@ $(TOUCH) -m position.hh --reference=position.hpp
	@ $(TOUCH) -m location.hh --reference=location.hpp

$(STATIC_BISON_HEADERS): $(ANY_BISON_FILE:.yy=.tab.cpp)

%.o: %.cpp
	@ $(ECHO) "Compiling: $<"
	@ $(CXX) $(CXXFLAGS) -c $< -o $@

%.d: %.cpp $(GENERATED_HEADERS)
	@ $(ECHO) "Finding dependencies: $<"
	@ $(SHELL) -ec '$(CXX) -MM -I$(ROOT) $< | sed '\''s!$(notdir $*)\.o[ :]*!$*.o $*.d : !'\'' > $@; [ -s $@ ] || $(RM) $@'

%: $(OBJECTS) %.o
	@ $(ECHO) "Linking: <sources>.o $*.o"
	@ $(CXX) $(CXXFLAGS) $(LINKFLAGS) -o $@ $^

################################################################################
